#pragma once 
#include <bits/stdc++.h>
#include "Any.hpp"

/*****************************************************************************
 *! @brief IoC: Inversion of Control  让两个对象的依赖不是基于特定的构造函数，也是依赖于
 *         某种机制，外接可以灵活配置这种机制的对象创建策略, 从而获得想要的目标对象, 这种机制
 *         被称为控制反转.
 * 
 *     控制反转就是应用本身不负责依赖对象的创建和维护，而交给一个外部容器来负责. 这样控制权就由
 *  应用本身转移到了外部IoC容器, 即实现了所谓的控制反转. IoC用来降低对象之间的直接依赖产生的耦
 *  合性。
 ****************************************************************************/

class NonCopyable {
public:
    // 使用默认无参构造函数
    NonCopyable() = default;

    //! 禁用拷贝构造函数 
    NonCopyable(const NonCopyable& rhs)            = delete;
    
    //! 禁用赋值函数 
    NonCopyable& operator=(const NonCopyable& rhs) = delete;
};

class IocContainer : NonCopyable {
public:
	IocContainer(void){}
	~IocContainer(void){}

    //! Case-1 T与Depend是继承关系
	template<class T, typename Depend, typename... Args>
	typename std::enable_if<std::is_base_of<T, Depend>::value>::type  registerType(const std::string& strKey) {
        // 通过闭包擦除了参数类型
		std::function<T* (Args...)> function = [](Args... args){ return new Depend(args...); };
		registerType(strKey, function);
	}

    //! Case-2 T与Depend不是继承关系
    template<class T, typename Depend, typename... Args>
	typename std::enable_if<!std::is_base_of<T, Depend>::value>::type  registerType(const std::string& strKey) {
        // 通过闭包擦除了参数类型
		std::function<T* (Args...)> function = [](Args... args){ return new T(new Depend(args...)); };
		registerType(strKey, function);
	}


    //! Case-3 普通类型对象支持
    //! TODO: 这里匹配还有问题，待完善
    // template<class T, typename... Args>
	// void registerType(const std::string& strKey) {
    //     // 通过闭包擦除了参数类型
	// 	std::function<T* (Args...)> function = [](Args... args){ return new T(args...); };
	// 	registerType(strKey, function);
	// }


	template<class T, typename... Args>
	T* resolve(const std::string& strKey, Args... args) {
		if (m_creatorMap.find(strKey) == m_creatorMap.end())
			return nullptr;

		Any resolver = m_creatorMap[strKey];
		std::function<T* (Args...)> function = resolver.AnyCast<std::function<T* (Args...)>>();

		return function(args...);
	}

	template<class T, typename... Args>
	std::shared_ptr<T> resolveShared(const std::string& strKey, Args... args) {
		T* t = resolve<T>(strKey, args...);

		return std::shared_ptr<T>(t);
	}

private:
	void registerType(const std::string& strKey, Any constructor) {
		if (m_creatorMap.find(strKey) != m_creatorMap.end())
			throw std::invalid_argument("this key has already exist!");

		//通过Any擦除了不同类型的构造器
		m_creatorMap.emplace(strKey, constructor);
	}

private:
	std::unordered_map<std::string, Any> m_creatorMap;
};